#pragma once

#include <iostream>
#include <string>
#include <cstdio>   // 这个头文件中有 popen函数
#include <cstring>
#include <set>

#include "log.hpp"
#include "Inetaddr.hpp"

using namespace log_namespace;

class Command
{
public:

    // 使用ls /usr/bin 可以看所有系统中的命令
    Command()
    {
        // 受限的命令
        _safeCommand.insert("ls");
        _safeCommand.insert("touch");
        _safeCommand.insert("which");
        _safeCommand.insert("pwd");
        _safeCommand.insert("whoami");
    }

    bool safecheck(const std::string &cmdstr)
    {
        for(auto& cmd : _safeCommand)
        {
            if (strncmp(cmd.c_str(), cmdstr.c_str(), cmd.size()) == 0);
            {
                return true;
            }
        }
        return false;
    }

    std::string execute(const std::string &cmdstr)
    {
        if (!safecheck(cmdstr))
        {
            return "unsafe";
        }
        

        std::string result;

        // popen 创建了一个子进程，执行一个字符串代表的命令后，
        // 将结果返回到fp中
        FILE* fp = popen(cmdstr.c_str(), "r");
        if (fp)
        {
            char line[1024];
            while (fgets(line, sizeof(line), fp))
            {
                result += line;
            }
            return result.empty() ? "success" : result;
        }
        return "execute error";
    }

    void handleCommand(int socketfd, inetAddr addr)
    {
        
        // 下面是一个长服务的程序
        while (true)
        {
            char commandbuff[1024];
            // recv 是专门面向字节流式的读取的一个接口
            // 下面这句代码
            ssize_t n = ::recv(socketfd, commandbuff, sizeof(commandbuff) - 1, 0);
            if (n > 0)
            {
                commandbuff[n] = 0;
                LOG(INFO, "get command from client %s, message: %s\n", addr.addrStr().c_str(), commandbuff);
                std::string result = execute(commandbuff);
                ::send(socketfd, result.c_str(), result.size(), 0);
            }
            else if(n == 0)
            {
                LOG(INFO, "client %s quit\n", addr.addrStr().c_str());
                break;
            }
            else
            {
                LOG(ERROR, "read error: %s\n", addr.addrStr().c_str());
                break;
            }
        }
        ::close(socketfd);
    }

    ~Command()
    {

    }
private:
    std::set<std::string> _safeCommand;
};
